﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Fishpark.PdfWriter.Linearisation
{
    /// <summary>
    /// The PdfObjectNode class represents a PDF object and all its related objects. These are the objects it refers to, and can be seen
    /// as child objects. Together, the nodes form a tree that displays the dependency chain of all objects in the document.
    /// This class is used by the PdfLineariser to determine the order in which to output objects to the linearised document.
    /// </summary>
    internal class PdfObjectNode
    {
        // Private fields
        // ==============
        #region Private fields
        private List<PdfObjectNode> _children;
        private PdfObjectReference _objectReference;
        #endregion



        // Public properties
        // =================
        #region Public properties
        /// <summary>
        /// Retrieves the object reference that this node represents.
        /// </summary>
        public PdfObjectReference ObjectReference
        {
            get { return _objectReference; }
        }

        public IEnumerable<PdfObjectNode> Children
        {
            get { return _children; }
        }
        #endregion



        // Public methods
        // ==============
        #region Public methods
        /// <summary>
        /// Adds the specified node to the list of children of this node.
        /// </summary>
        /// <param name="node">The node to add</param>
        public void Add(PdfObjectNode node)
        {
            if (null == node) throw new ArgumentNullException("node");

            _children.Add(node);
        }

        public void DebugWrite(System.IO.TextWriter writer)
        {
            WriteToStream(writer, 0, new Stack<PdfObjectNode>());
        }

        private void WriteToStream(System.IO.TextWriter writer, int indent, Stack<PdfObjectNode> stack)
        {
            writer.WriteLine(String.Format("{0}{1}", new String(' ', indent), this.ObjectReference));
            if (false == stack.Contains(this))
            {
                stack.Push(this);
                
                foreach (PdfObjectNode node in _children)
                    node.WriteToStream(writer, indent + 2, stack);

                stack.Pop();

            }
        }

        #endregion



        // Public constructor
        // ==================
        #region Public constructor
        /// <summary>
        /// Constructs a new PdfObjectReference instance
        /// </summary>
        /// <param name="objectReference">The object reference that this node represents.</param>
        public PdfObjectNode(PdfObjectReference objectReference)
        {
            if (objectReference.IsEmpty())
                throw new ArgumentException("The object reference can not be empty", "objectReference");

            _objectReference = objectReference;
            _children = new List<PdfObjectNode>();
        }
        #endregion

    } // PdfObjectNode class
}
